Можно ли добавить к innerHTML, не уничтожая слушателей событий потомков? - PullRequest
86 голосов
/ 27 февраля 2009

В следующем примере кода я присоединяю обработчик события onclick к диапазону, содержащему текст «foo». Обработчик является анонимной функцией, которая выдает alert().

Однако, если я назначу родительский узел innerHTML, этот обработчик событий onclick будет уничтожен - нажатие "foo" не сможет вызвать окно предупреждения.

Это поправимо?

<html>
 <head>
 <script type="text/javascript">

  function start () {
    myspan = document.getElementById("myspan");
    myspan.onclick = function() { alert ("hi"); };

    mydiv = document.getElementById("mydiv");
    mydiv.innerHTML += "bar";
  }

 </script>
 </head>

 <body onload="start()">
   <div id="mydiv" style="border: solid red 2px">
     <span id="myspan">foo</span>
   </div>
 </body>

</html>

Ответы [ 12 ]

111 голосов
/ 27 февраля 2009

К сожалению, присвоение innerHTML вызывает уничтожение всех дочерних элементов, даже если вы пытаетесь добавить. Если вы хотите сохранить дочерние узлы (и их обработчики событий), вам нужно использовать функции DOM :

function start() {
    var myspan = document.getElementById("myspan");
    myspan.onclick = function() { alert ("hi"); };

    var mydiv = document.getElementById("mydiv");
    mydiv.appendChild(document.createTextNode("bar"));
}

Редактировать: Решение Боба, из комментариев. Отправь свой ответ, Боб! Получите кредит за это. : -)

function start() {
    var myspan = document.getElementById("myspan");
    myspan.onclick = function() { alert ("hi"); };

    var mydiv = document.getElementById("mydiv");
    var newcontent = document.createElement('div');
    newcontent.innerHTML = "bar";

    while (newcontent.firstChild) {
        mydiv.appendChild(newcontent.firstChild);
    }
}
47 голосов
/ 07 декабря 2016

Использование .insertAdjacentHTML() сохраняет прослушиватели событий, а поддерживается всеми основными браузерами . Это простая однострочная замена для .innerHTML.

var html_to_insert = "<p>New paragraph</p>";

// with .innerHTML, destroys event listeners
document.getElementById('mydiv').innerHTML += html_to_insert;

// with .insertAdjacentHTML, preserves event listeners
document.getElementById('mydiv').insertAdjacentHTML('beforeend', html_to_insert);

Аргумент 'beforeend' указывает, где в элементе вставлять содержимое HTML. Возможные варианты: 'beforebegin', 'afterbegin', 'beforeend' и 'afterend'. Их соответствующие местоположения:

<!-- beforebegin -->
<div id="mydiv">
  <!-- afterbegin -->
  <p>Existing content in #mydiv</p>
  <!-- beforeend -->
</div>
<!-- afterend -->
4 голосов
/ 20 января 2012

Теперь наступил 2012 год, и в jQuery есть функции добавления и добавления, которые делают именно это, добавляют контент, не влияя на текущий контент. Очень полезно.

3 голосов
/ 28 февраля 2009

В качестве небольшой (но связанной) подсказки, если вы используете библиотеку javascript, такую ​​как jquery (v1.3), для выполнения ваших dom-манипуляций, вы можете использовать живые события, посредством которых вы устанавливаете обработчик, такой как:

 $("#myspan").live("click", function(){
  alert('hi');
});

и он будет постоянно применяться к этому селектору при любых видах манипуляций с jquery. Для живых событий смотрите: docs.jquery.com / events / live для манипуляций с jquery смотрите: docs.jquery.com / манипулирование

2 голосов
/ 12 июля 2018

something.innerHTML + = 'добавь, что хочешь';

это сработало для меня. Я добавил кнопку для ввода текста, используя это решение

2 голосов
/ 04 июля 2012

Я создал свою разметку для вставки в виде строки, так как она меньше кода и ее легче читать, чем работать с модными штуками.

Затем я сделал это innerHTML временным элементом, чтобы я мог взять единственного потомка этого элемента и прикрепить его к телу.

var html = '<div>';
html += 'Hello div!';
html += '</div>';

var tempElement = document.createElement('div');
tempElement.innerHTML = html;
document.getElementsByTagName('body')[0].appendChild(tempElement.firstChild);
1 голос
/ 27 июня 2018

Существует другая альтернатива: использование setAttribute вместо добавления прослушивателя событий. Как это:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Demo innerHTML and event listeners</title>
<style>
    div {
        border: 1px solid black;
        padding: 10px;
    }
</style>
</head>
<body>
    <div>
        <span>Click here.</span>
    </div>
    <script>
        document.querySelector('span').setAttribute("onclick","alert('Hi.')");
        document.querySelector('div').innerHTML += ' Added text.';
    </script>
</body>
</html>
0 голосов
/ 02 мая 2019

Да, это возможно, если вы связываете события, используя аргумент onclick="sayHi()" непосредственно в шаблоне, аналогичном вашему <body onload="start()"> - этот подход аналогичен фреймворкам angular / vue / реакции / и т. Д. Вы также можете использовать <template> для работы с «динамическим» html, например здесь . Это не является строгим ненавязчивым JS, однако это приемлемо для небольших проектов

function start() {
  mydiv.innerHTML += "bar";
}

function sayHi() {
  alert("hi");
}
<body onload="start()">
  <div id="mydiv" style="border: solid red 2px">
    <span id="myspan" onclick="sayHi()">foo</span>
  </div>
</body>
0 голосов
/ 24 октября 2018

Самый простой способ - использовать массив и помещать в него элементы, а затем динамически вставлять последующие значения в массив. Вот мой код:

var namesArray = [];

function myclick(){
    var readhere = prompt ("Insert value");
    namesArray.push(readhere);
    document.getElementById('demo').innerHTML= namesArray;
}
0 голосов
/ 27 марта 2014

Вы можете сделать это так:

var anchors = document.getElementsByTagName('a'); 
var index_a = 0;
var uls = document.getElementsByTagName('UL'); 
window.onload=function()          {alert(anchors.length);};
for(var i=0 ; i<uls.length;  i++)
{
    lis = uls[i].getElementsByTagName('LI');
    for(var j=0 ;j<lis.length;j++)
    {
        var first = lis[j].innerHTML; 
        string = "<img src=\"http://g.etfv.co/" +  anchors[index_a++] + 
            "\"  width=\"32\" 
        height=\"32\" />   " + first;
        lis[j].innerHTML = string;
    }
}
...